import {
  AfterViewChecked,
  ChangeDetectionStrategy,
  ViewEncapsulation,
  Component,
  Input,
  OnInit,
  Output,
  EventEmitter,
  ViewChild,
  ElementRef,
  ChangeDetectorRef,
  SimpleChanges,
  OnChanges,
  ViewChildren,
  QueryList,
  OnDestroy,
  AfterViewInit,
  Renderer2,
  TemplateRef,
} from '@angular/core';
import { cloneDeep } from 'lodash';
import { fromEvent, merge, skip, Subject, Subscription } from 'rxjs';
import {
  DateService,
  I18NService,
  InputBoolean,
  isEmpty,
  LvDateMode,
  OverlayService,
  ResizeObserverObject,
  ResizeObserverService,
  TypeUtils,
} from '../core/api';
import { OverflowDirective } from '../overflow/overflow.directive';
import { type TreeNode } from '../tree/interface';
import { PopoverDirective } from '../popover/popover.directive';
import { OptionItem } from '../select/interface';
import { SelectComponent } from '../select/select.component';
import { TagItem } from '../tag/interface';
import { FieldItem, FilterMode, FilterState, FilterTagItem, RecommendedValue } from './interface';
import { SearchService } from './search.service';

const dateService = new DateService();
const NUMBER_MODES = [
  {
    label: 'advancedFilterMore',
    value: 'more',
  },
  {
    label: 'advancedFilterLess',
    value: 'less',
  },
  {
    label: 'advancedFilterEquals',
    value: 'equals',
  },
  {
    label: 'advancedFilterRangeIn',
    value: 'rangeIn',
  },
];

const TEXT_MODES = [
  {
    label: 'advancedFilterStartsWith',
    value: 'startsWith',
  },
  {
    label: 'advancedFilterEndsWith',
    value: 'endsWith',
  },
  {
    label: 'advancedFilterContains',
    value: 'contains',
  },
];

const DATE_FORMAT = {
  date: 'yyyy-MM-dd',
  month: 'yyyy-MM',
  year: 'yyyy',
  simple: 'yyyy-MM-dd',
};

const PANEL_FIELD_TYPE_CONFIG: {
  [key: string]: {
    [key: string]: any;
    header?: boolean;
    footer?: boolean;
    'space-size'?: string;
    modes?: Array<{ label: string; value: string }>;
    value?: any; // 初始值
    defaultMode?: FilterMode;
    label?: any;
    template?: string;
  };
} = {
  single: {
    label: (val): any => val?.label,
    defaultValue: (item): any => item.option?.items?.find((temp): boolean => temp.value === item.defaultValue),
  },
  multiple: {
    footer: true,
    'space-size': '8px',
    value: [],
    label: (val): any => val?.map((item) => item.label).join(','),
    defaultValue: (item): any => item.option?.items?.filter((temp): any => item.defaultValue.includes(temp.value)),
  },
  number: {
    header: true,
    footer: true,
    'space-size': '16px',
    modes: NUMBER_MODES,
    value: 0,
    defaultMode: 'equals',
    label: (val): string => val.toString(),
    defaultValue: (item) => item.defaultValue,
  },
  numberRange: {
    header: true,
    footer: true,
    'space-size': '16px',
    modes: NUMBER_MODES,
    value: [0, 0],
    defaultMode: 'rangeIn',
    label: ([start, end]): string => `${start}~${end}`,
    defaultValue: (item) => item.defaultValue,
  },
  textInput: {
    header: true,
    footer: true,
    'space-size': '16px',
    modes: TEXT_MODES,
    value: '',
    defaultMode: 'endsWith',
    label: (val) => val,
    defaultValue: (item) => item.defaultValue,
  },
  datePicker: {
    value: null,
    label: (val, format): string => dateService.format(val, format),
    defaultValue: (item) => item.defaultValue,
  },
  dateRangePicker: {
    footer: true,
    'space-size': '16px',
    value: [],
    label: (val): string => `${dateService.format(val[0], 'yyyy-MM-dd')}~${dateService.format(val[1], 'yyyy-MM-dd')}`,
    defaultValue: (item) => item.defaultValue,
  },
  treeSingle: {
    value: '',
    label: (val) => val[0].label,
    defaultValue: (item) => item.defaultValue,
  },
  treeMultiple: {
    footer: true,
    'space-size': '8px',
    value: [],
    label: (val): any => val?.map((item) => item.label).join(','),
    defaultValue: (item) => item.defaultValue,
  },
  customize: {
    value: null,
    label: (val) => val,
    defaultValue: (item) => item.defaultValue,
  },
};

@Component({
  selector: 'lv-advanced-filter',
  exportAs: 'lvAdvancedFilter',
  templateUrl: './advanced-filter.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  host: {
    class: 'lv-advanced-filter',
    '(keydown)': 'onKeyDown($event)',
    tabindex: '-1',
  },
})
export class AdvancedFilterComponent implements OnInit, AfterViewChecked, OnChanges, OnDestroy, AfterViewInit {
  @Input() lvFields: FieldItem[];
  @Input() lvTagMaxWidth = '100%';
  @Input() lvMaxTagRow: number = 3;
  @Input() lvCustomButton: TemplateRef<any>;
  @Input() @InputBoolean() lvSearchable = true;
  @Input() lvTreeFiltersHeader: TemplateRef<any>;
  @Input() @InputBoolean() lvWrap: boolean = false;
  @Input() @InputBoolean() lvSearchKeyWordAble = true;
  @Input() lvSearchKeyWord = this.i18n.get('keyword');
  @ViewChild('lvPopover') lvPopover: PopoverDirective;
  @ViewChild(SelectComponent) lvSelect: SelectComponent;

  @Input() lvFilterPanelType: 'tree' | 'normal' = 'normal';

  @ViewChildren('lvOverflow') lvOverflow: QueryList<OverflowDirective>;
  @ViewChild('advancedFilter') advancedFilter: ElementRef<HTMLElement>;
  @ViewChild('advancedWrapper') advancedWrapper: ElementRef<HTMLElement>;
  @Input() lvPlaceholder: string = this.i18n.get('advancedFilterPlaceholder');
  @ViewChildren('lvTag', { read: ElementRef }) lvTag: QueryList<ElementRef<HTMLElement>>;
  @ViewChild('inputContent', { read: ElementRef, static: true }) _inputElementRef: ElementRef;

  @Output() lvOnChange = new EventEmitter<{ selectedFilters: FilterState[]; currentFilter: FilterState }>(); // 删除，新增，修改过滤器回调

  public filterValue: any; // 当前过滤器的值
  public searchInput = '';
  public spaceSize: string; // 具体过滤器面板的header，content，footer间距
  public hasHeader: boolean; // 当前过滤器是否需要header显示
  public hasFooter: boolean; // 当前过滤器是否需要footer显示
  public fieldInfoOption: any; // 保存当前过滤器中的option选项
  public filters: OptionItem[]; // 可选择的过滤器集合(除去已选择的过滤器)
  public checkedTag: TagItem[]; // 当前选中的tag值
  public typeUtils = TypeUtils;
  public filterMode: FilterMode; // 当前过滤器选中的mode
  public pickerMode: LvDateMode; // datePicker类型过滤器模式
  public treeFilters: TreeNode[]; // 下拉筛选面板树形结构数据
  public tags: FilterTagItem[] = []; // 用于保存过滤后显示的tag
  public filterOption: OptionItem[]; // 当前过滤器的option选项(单选和多选存在)
  public currentFilter: FilterState; // 当前选中的过滤器
  public showTags: FilterTagItem[] = []; // 用于保存视图显示的tag
  public isFilterPanel: boolean = false; // 决定当前弹出过滤器集合或具体某个过滤器面板

  public searchFilters: OptionItem[] = [];
  public advancedWrapperHasScroll = false;
  public contextValue: { filterValue: any }; // 作为模板变量传入使用
  public popoverRef: ElementRef<HTMLElement>; // popover面板的挂载源
  public typeConfig = PANEL_FIELD_TYPE_CONFIG;
  public headerModes: Array<{ label: string; value: string }>; // 过滤器header展示的mode列表
  public outerClosable: boolean | { exclusions: HTMLElement[] } = true;

  private isOverlay = false;

  private _isModify: boolean; // 标记当前是否修改过滤器值场景

  private manualItemClick = true;
  private mousemove: Subscription;
  private _isFirstShowLess: boolean; // 标记初始是否已经showLess
  private afterClose$ = new Subject<void>();
  private beforeOpen$ = new Subject<void>();
  private syncPopoverVisible: boolean = false; // 控制下拉面板显示隐藏
  private $onMotionDone = new Subject<void>();
  private _selectedFilters: FilterState[] = []; // 当前已选择的过滤器及选择结果
  private advancedWrapperObserver: MutationObserver;
  private advancedWrapperResize: ResizeObserverObject;

  constructor(
    private _cdr: ChangeDetectorRef,
    private _el: ElementRef,
    public i18n: I18NService,
    private overlayService: OverlayService,
    private resizeObserverService: ResizeObserverService,
    private render: Renderer2,
    private searchService: SearchService,
  ) {}

  get popoverVisible(): boolean {
    return this.syncPopoverVisible;
  }

  set popoverVisible(value: boolean) {
    // false -> true && overlayRef 应该在afterClose后再赋值为true
    if (!this.popoverVisible && value && this.lvPopover?.popover._overlayRef?.overlayRef.hasAttached()) {
      const afterClose$ = this.afterClose$.subscribe((): void => {
        this.syncPopoverVisible = value;
        afterClose$.unsubscribe();
      });
    } else {
      this.syncPopoverVisible = value;
    }
  }

  afterClose = (): void => {
    this.afterClose$.next();
  };

  beforeOpen = (): void => {
    this.beforeOpen$.next();
  };

  onKeyDown(e: KeyboardEvent): void {
    this.lvSelect?.onKeyDown(e);
  }

  showSearchResult(): boolean {
    return this.searchInput && this.lvSearchable;
  }

  clearInput(): void {
    this._inputElementRef.nativeElement.value = '';
    this.searchInput = '';
  }

  /**
   * 控制过滤器集合下拉面板的显示隐藏
   */
  togglePopoverVisible(): void {
    this.popoverVisible = !this.popoverVisible;
    this._cdr.markForCheck();
  }

  /*
   * 1、鼠标移入的时候，如果lvWrap未传入不操作；
   * 2、否则设置showTags为展开的tags集合；
   */
  showMore(event: MouseEvent): void {
    event.stopPropagation();
    if (!this.lvWrap) {
      return;
    }
    this.showTags = this.tags;
    this.renderTagMaxWidth();
  }

  genIsFilterPanel(value: boolean): void {
    const sub$ = merge(this.afterClose$, this.beforeOpen$).subscribe((): void => {
      this.isFilterPanel = value;
      sub$.unsubscribe();
    });
  }

  checkHasScroll(): void {
    const wrapper = this.advancedWrapper.nativeElement;
    this.advancedWrapperHasScroll = wrapper.scrollWidth !== wrapper.clientWidth;
    this._cdr.markForCheck();
  }

  /**
   * 获取当前选中的筛选项
   */
  getSelectedValue(): FilterState[] {
    const _selectedFilters: FilterState[] = cloneDeep(this._selectedFilters);

    // 移除循环引用数据内容，防止json转字符串报错
    this.removeLoopReferences(_selectedFilters);
    return _selectedFilters;
  }

  /**
   * 用于从用户传入的lvFields API中获取下拉展示的过滤器集合
   */
  getFieldList(): void {
    this.filters = this.lvFields.map((item): any => ({
      label: item.label,
      value: item.field,
      isLeaf: true,
      disabled: item.disabled,
    }));
    this.treeFilters = this.getTreeFilters();
  }

  ngOnChanges(changes: SimpleChanges): void {
    const { lvFields: fieldsChange } = changes;

    // 后续添加已选择筛选器但是lvFields变化后筛选器不存在的逻辑
    if (!fieldsChange?.firstChange) {
      this.getFieldList();
      this.setDefaultValue();
    }
  }

  onTreePanelClick({ node }: { node: TreeNode }): void {
    if (node?.children) {
      return;
    }

    const selectedFilter: OptionItem = {
      label: node.label,
      value: node.value,
    };

    this.onSelectFilter(selectedFilter);
  }

  ngOnDestroy(): void {
    this.mousemove.unsubscribe();
    this.advancedWrapperResize.unobserve();
    this.advancedWrapperObserver.disconnect();
    this.$onMotionDone.complete();
    this.afterClose$.complete();
    this.beforeOpen$.complete();
  }

  /**
   * 所有过滤器确认后的回调
   */
  onConfirm(): void {
    if (this.fieldInfoOption?.render) {
      this.filterValue = this.contextValue.filterValue;
    }
    const valueLabel = this._getValueLabel(this.currentFilter.type, this.filterValue, this.pickerMode);
    this.onFilterConfirm(this.filterValue, valueLabel);
    this.checkedTag = [];
  }

  ngAfterViewChecked(): void {
    // 需要换行显示+已经存在tag+未执行过showLess逻辑
    if (this.lvWrap && this.tags.length && !this._isFirstShowLess) {
      const tagsList = this._el.nativeElement.querySelectorAll('.lv-tag-item');
      if (tagsList.length) {
        this.showLess();
        this._isFirstShowLess = true;
      }
    }
  }

  onMotionDone(): void {
    setTimeout((): void => {
      // 动效执行完外部容器滚动条还没有出现，下一周期检查
      this.checkHasScroll();
      this.outerClosable = {
        exclusions: this.lvTag.map((item): HTMLElement => item.nativeElement.querySelector('.lv-tag-remove')),
      };
      this.$onMotionDone.next();
      this._cdr.markForCheck();
    });
  }

  /**
   * 根据过滤器type类型和value，获取值的label显示
   */
  _getValueLabel(type: string, value: any, pickerMode?: LvDateMode): string {
    let valueLabel;
    if (type === 'datePicker') {
      valueLabel = this.typeConfig[type].label(value, DATE_FORMAT[pickerMode || 'date']);
    } else {
      valueLabel = this.fieldInfoOption?.label?.(value) || this.typeConfig[type].label(value);
    }
    return valueLabel;
  }

  isClickItem(e?: { target: HTMLElement; type: string }): boolean {
    if (!e) {
      return false;
    }
    if (this.overlayService.getTargetNode(e.target, this._inputElementRef.nativeElement)) {
      return true;
    }
    for (const tag of this.lvTag) {
      if (this.overlayService.getTargetNode(e.target, tag.nativeElement)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 点击清除按钮的回调
   */
  onClearAll(e: MouseEvent): void {
    e.stopPropagation();
    this.tags = [];
    this.showTags = this.tags;
    this.renderTagMaxWidth();
    this._selectedFilters = [];
    this.currentFilter = null;
    this.getFieldList();
    this.genIsFilterPanel(false);
    this.popoverVisible = false;
    this.lvOnChange.emit({ selectedFilters: this._selectedFilters, currentFilter: this.currentFilter });
  }

  /**
   * 数字类型过滤器，mode从rangeIn切换到其他或者其他切换到rangeIn，需要同时修改过滤器type
   */
  onModeChange(): void {
    if (this.currentFilter.type === 'number' && this.filterMode === 'rangeIn') {
      this.currentFilter.type = 'numberRange';
      this.filterValue = [...this.typeConfig[this.currentFilter.type].value];
    } else if (this.currentFilter.type === 'numberRange' && this.filterMode !== 'rangeIn') {
      this.currentFilter.type = 'number';
      this.filterValue = this.typeConfig[this.currentFilter.type].value;
    }
  }

  ngAfterViewInit(): void {
    const wrapper = this.advancedWrapper.nativeElement;
    this.checkHasScroll();
    this.advancedWrapperObserver = new MutationObserver((): void => {
      this.checkHasScroll();
    });
    this.advancedWrapperObserver.observe(wrapper, {
      childList: true,
      subtree: true,
    });
    this.advancedWrapperResize = this.resizeObserverService.observe(wrapper, (): void => {
      this.checkHasScroll();
    });
    this.renderTagMaxWidth();
  }

  /**
   * input点击的回调，如果之前时处于修改状态，设置修改状态为false
   */
  onInputClick(): void {
    this.popoverRef = this._inputElementRef;
    this._inputElementRef.nativeElement.focus();
    this._inputElementRef.nativeElement.scrollIntoView({ block: 'nearest', inline: 'nearest' });
    this._cdr.detectChanges();
    if (this.popoverVisible && this.isFilterPanel) {
      this.onCancel();
    }
    if (this._isModify) {
      this._isModify = false;
      this.genIsFilterPanel(false);
    }
    this.popoverVisible = true;
    this._cdr.markForCheck();
  }

  onInput(value: string): void {
    if (!this.lvSearchable) {
      return;
    }
    this.searchInput = value;
    this.popoverRef = this._inputElementRef;
    this.popoverVisible = true;
    this.searchFilters = this.searchService.getSearchFilters(
      this.searchService.getFilter(value, this.lvFields),
      this.searchService.getRecommendedSearch(value, this.lvFields, {
        searchKeyWordAble: this.lvSearchKeyWordAble,
        searchKeyWord: this.lvSearchKeyWord,
      }),
    );
    this._cdr.markForCheck();
  }

  /*
   * 1、鼠标移开的时候，如果lvWrap未传入或者当前处于选择状态（popoverVisible或isFilterPanel是true）不操作；
   * 2、否则判断当前tags的总宽度是否超过总的显示宽度，如果未超过，不需要操作；
   * 3、超过总宽度，设置showTags为带+num标签的tags集合；
   */
  showLess(event?: MouseEvent): void {
    event?.stopPropagation();
    if (!this.lvWrap || this.popoverVisible || this.lvPopover?.popover._overlayRef?.overlayRef.hasAttached()) {
      return;
    }
    const [needShowLess, tagIndex] = this.calTagsWidth();

    if (needShowLess && this.tags.length - tagIndex > 0) {
      const lessTags = this.tags.slice(0, tagIndex);
      const newTag: FilterTagItem = {
        label: `+${this.tags.length - lessTags.length}`,
        field: 'numTag',
        removable: false,
      };
      lessTags.push(newTag);
      this.showTags = lessTags;
      this.renderTagMaxWidth();
    }
  }

  /**
   * 移除tag的回调
   * 1、移除的过滤器重新加入到可选择集合中
   * 2、内部保存的已选择过滤器中删除该过滤器
   * 3、如果删除的tag是未选择完成的过滤器逻辑处理
   * @param tag 删除的tag标签
   */
  onRemoveTag(tag: FilterTagItem): void {
    const filterIndex = this._selectedFilters.findIndex((item): boolean => item.field === tag.field);
    if (filterIndex === -1) {
      this.onCancel();
      return;
    }
    const filter = this._selectedFilters[filterIndex];
    this._selectedFilters.splice(filterIndex, 1);
    if (filter.field === this.currentFilter?.field) {
      this.currentFilter.field = undefined;
    }
    this.lvOnChange.emit({ selectedFilters: this._selectedFilters, currentFilter: filter });
    this.tags.splice(
      this.tags.findIndex((item): boolean => item.field === tag.field),
      1,
    );
    this._addFilter(tag.field);
    this.onCancel();
  }

  /**
   * 判断当前tags加上+num标签后是否超长
   * 如果超长返回[true, num]，num为第一个无法显示的tag下标
   * 如果不超长返回[false, -1]
   */
  calTagsWidth(): [boolean, number] {
    // +num标签占用的宽度，本身23 px加上padding和margin 20px，共43px
    const addTagWidth = 43;
    // input占用的固定宽度
    const inputWidth = 194;
    // tags剩余可用宽度
    let restWidth = this._el.nativeElement.querySelector('.lv-advanced-filter-tag-container').clientWidth - inputWidth;
    const tagsList = this._el.nativeElement.querySelectorAll('.lv-tag-item');

    for (let i = 0; i < tagsList.length; i++) {
      // 在进行当前tag宽度比较之前，先判断下num tag是否还能放下，如果num tag已经无法放下直接返回
      if (restWidth < addTagWidth) {
        return [true, i - 1];
      }
      if (tagsList[i].clientWidth + 8 > restWidth) {
        return [true, i];
      }
      // 每个tag还有8 px的margin宽度
      restWidth = restWidth - tagsList[i].clientWidth - 8;
    }

    return [false, -1];
  }

  ngOnInit(): void {
    this.genIsFilterPanel(false);
    this.showTags = this.tags;
    this.popoverRef = this._inputElementRef;
    this.getFieldList();
    this.setDefaultValue();
    this.mousemove = fromEvent(document, 'mousemove').subscribe((event: MouseEvent): void => {
      this.isOverlay = false;
      for (const item of this.lvOverflow
        .toArray()
        .map(
          (curItem): Element => curItem?._componentRef?.instance?._overlayRef?.overlayRef?._portalOutlet?.outletElement,
        )
        .filter((curItem): Element => curItem)) {
        this.isOverlay = this.overlayService.getTargetNode(event.target, item);
        if (this.isOverlay) {
          break;
        }
      }
      if (this.overlayService.getTargetNode(event.target, this.advancedFilter.nativeElement)) {
        this.showMore(event);
      } else {
        this.showLess(event);
      }
      this._cdr.markForCheck();
    });
  }

  /**
   *
   * @param config { includeFields: 应包含的筛选项 }
   * @returns 树形数据结构的filters
   */
  getTreeFilters(config?: { includeFields?: Array<string | number> }): TreeNode[] {
    const { includeFields } = config ?? {};

    const treeFilters: TreeNode[] = [];
    const treeFiltersTypeMap: Map<string, number> = new Map();

    // 按传入group分类，形成树形结构
    this.lvFields.forEach((item): void => {
      if (includeFields && !includeFields?.includes(item.field)) {
        return;
      }

      if (item.group) {
        const treeFiltersTypeIndex = treeFiltersTypeMap.get(item.group);

        if (treeFiltersTypeIndex !== undefined) {
          treeFilters[treeFiltersTypeIndex].children.push({ label: item.label, value: item.field, isLeaf: true });
          return;
        }

        treeFilters.push({ label: item.group, children: [{ label: item.label, value: item.field, isLeaf: true }] });
        treeFiltersTypeMap.set(item.group, treeFilters.length - 1);
        return;
      }

      treeFilters.push({ label: item.label, value: item.field, isLeaf: true });
    });
    return treeFilters;
  }

  /**
   * 具体筛选器选择后，设置不同类型筛选器的面板(新增筛选器和修改筛选器调用)
   */
  setPanelFilter(): void {
    if (this.currentFilter.type === 'numberRange') {
      this.filterValue = [...this.typeConfig[this.currentFilter.type].value];
    } else {
      this.filterValue = this.typeConfig[this.currentFilter.type].value;
    }

    this.contextValue = { filterValue: this.filterValue };

    this.fieldInfoOption = this.currentFilter.fieldInfo.option;
    this.filterOption = this.fieldInfoOption?.items?.map((item): any => ({
      label: item.label,
      value: item.value,
      isLeaf: true,
      disabled: item.disabled,
    }));
    this.pickerMode = this.fieldInfoOption?.lvPickerMode || 'date';

    ({
      header: this.hasHeader,
      footer: this.hasFooter,
      'space-size': this.spaceSize,
      modes: this.headerModes,
      defaultMode: this.filterMode,
    } = this.typeConfig[this.currentFilter.type]);
    const { modeChangeDisable } = this.currentFilter.fieldInfo;
    this.hasHeader = this.hasHeader && !modeChangeDisable;

    this.filterMode = this.currentFilter.filterMode;
  }

  /**
   * 过滤器选择的回调
   * 1、通过currentFilter保存当前过滤器信息
   * 2、设置选中过滤器的筛选面板
   * 3、从可选择的过滤项集合中删除当前选中的过滤器
   * 4、添加选中过滤器的tag
   * @param selectedFilter 选中的过滤器
   */
  onSelectFilter(selectedFilter: OptionItem): void {
    if (selectedFilter.value instanceof Object) {
      const value = selectedFilter.value as RecommendedValue;
      this.doAfterFindTag({ label: value.label, value: value.field }, (_, tagItem): void => {
        this.setCurrentFilter(tagItem, null);
        this.filterMode = this.currentFilter.filterMode;
        this._isModify = true;
        this.onFilterConfirm(value.value, value.value);
        this.clearInput();
      });
    } else {
      this.togglePopoverVisible();

      const filter = this.lvFields.find((item): boolean => item.field === selectedFilter.value);
      this.currentFilter = {
        field: filter.field,
        fieldInfo: filter,
        filterMode: filter.mode || 'contains',
        type: filter.type,
      };
      this.setPanelFilter();
      this.doAfterFindTag(selectedFilter, (tagIndex): void => {
        this.genIsFilterPanel(true);
        const sub = this.$onMotionDone.pipe(skip(1)).subscribe((): void => {
          this.clearInput();
          this.openPopoverByTagIndex(tagIndex);
          sub.unsubscribe();
        });
      });
    }
  }

  /**
   * tag点击的的回调
   * 1、如果是对之前已选择过滤器的修改，则配置currentFilter及面板值
   * 2、设置当前点击的tag为popover的挂载源
   * 3、弹出下拉面板，并标记_isModify为true
   * @param selectedFilter 选中的过滤器
   */
  onClickTag(tag: FilterTagItem): void {
    if (tag === this.checkedTag?.[0] && this.popoverVisible) {
      const tagIndex = this.tags.findIndex((item): boolean => item.field === tag.field);
      this.onCancel({ target: this.lvTag.get(tagIndex).nativeElement, type: 'click' });
      return;
    }
    const filter = this._selectedFilters.find((item): boolean => item.field === tag.field);
    const sub$ = this.beforeOpen$.subscribe((): void => {
      this.setCurrentFilter(tag, filter);
      this.setPanelFilter();
      if (filter) {
        this.filterValue = filter.filteredValue;
      }
      this.contextValue = { filterValue: this.filterValue };
      this.checkedTag = [tag];
      sub$.unsubscribe();
    });
    this.genIsFilterPanel(true);

    const tagIndex = this.tags.findIndex((item): boolean => item.field === tag.field);
    this.popoverRef = this.lvTag.get(tagIndex);
    this.popoverRef?.nativeElement.scrollIntoView({ block: 'nearest', inline: 'nearest' });
    this.popoverVisible = true;
    this._cdr.detectChanges();
    this._isModify = this.manualItemClick ? true : this._isModify;
    this.manualItemClick = true;
  }

  /**
   * 根据传入value设置当前筛选项
   */
  setCustomFilters(value: FilterState[]): void {
    this.currentFilter = null;

    const selectedFilters = cloneDeep(value) || [];

    this._selectedFilters = selectedFilters;

    const selectedField = selectedFilters.map((item) => item.field);

    this.filters = this.lvFields
      .map((item): any => ({
        label: item.label,
        value: item.field,
        isLeaf: true,
        disabled: item.disabled,
      }))
      .filter((item): boolean => !selectedField.includes(item.value));
    this.treeFilters = this.getTreeFilters({ includeFields: this.filters.map((item): any => item.value) });

    this.tags = selectedFilters.map((item): { field: any; removable: boolean; label: string } => ({
      label: `${item.fieldInfo.label}: ${this._getValueLabel(item.type, item.filteredValue, this.pickerMode)}`,
      field: item.field,
      removable: true,
    }));
    this.showTags = this.tags;

    this._inputElementRef.nativeElement.scrollIntoView({ block: 'nearest', inline: 'nearest' });
    this.popoverRef = this._inputElementRef;

    this.genIsFilterPanel(false);

    this.lvOnChange.emit({ selectedFilters: this._selectedFilters, currentFilter: { ...this.currentFilter } });
    this.renderTagMaxWidth();
  }

  /**
   * 用户传入的lvFields中存在defaultValue时处理
   * 1、过滤器集合中取出该筛选器
   * 2、生成对应的tag标签
   * 3、selectedFilters中添加对应的过滤器结果
   */
  setDefaultValue(): void {
    this.lvFields.forEach((item): void => {
      if (this.typeUtils.isNil(item.defaultValue)) {
        return;
      }
      this.filters.splice(
        this.filters.findIndex((filter): boolean => filter.value === item.field),
        1,
      );
      this.treeFilters = this.getTreeFilters({ includeFields: this.filters.map((curItem): any => curItem.value) });

      const value = this.typeConfig[item.type].defaultValue(item);
      const valueLabel = this._getValueLabel(item.type, value, item.option?.pickerMode);

      // tags会添加相同的field且label不相同的对象，需要对tags过滤重新赋值
      const sameFieldIndex: number = this.tags.findIndex((tag: FilterTagItem): boolean => tag.field === item.field);
      if (sameFieldIndex < 0) {
        const newTag: FilterTagItem = { label: `${item.label}: ${valueLabel}`, field: item.field, removable: true };
        this.tags.push(newTag);
      } else {
        this.tags[sameFieldIndex] = { field: item.field, removable: true, label: `${item.label}: ${valueLabel}` };
      }

      this._selectedFilters.push({
        field: item.field,
        fieldInfo: item,
        filterMode: item.mode || 'contains',
        filteredValue: value,
        type: item.type,
      });
    });
  }

  /**
   * 单击取消按钮、点击面板外部触发
   */
  onCancel(e?: { target: HTMLElement; type: string }): void {
    if (this._isModify || !this.isFilterPanel || ['mousewheel', 'scroll'].includes(e?.type)) {
      this.checkedTag = [];
      // 筛选类型面板打开时点击外部框不执行cancel逻辑
      if (
        e?.target &&
        this.overlayService.getTargetNode(e.target, this.advancedFilter.nativeElement) &&
        !this.isClickItem(e)
      ) {
        return;
      }
      this.popoverVisible = false;
      this.genIsFilterPanel(false);
      // 多行的时候判断可点击元素触发
      if (!this.isClickItem(e)) {
        const sub$ = this.afterClose$.subscribe((): void => {
          this.showLess();
          sub$.unsubscribe();
        });
      }
      if (this.currentFilter?.field && this.getCurrentFilterIndex() === -1) {
        this.tags.splice(-1, 1);
        this._addFilter(this.currentFilter.field);
        this.currentFilter.field = undefined; // 滚动连续触发的时候锁住
      }
      this.clearInput();
      return;
    }
    this.currentFilter.filteredValue = '';
    const tagIndex = this.getTagIndex();
    this.checkedTag = [];
    if (tagIndex !== -1) {
      this.tags.splice(tagIndex, 1);
      this._addFilter(this.currentFilter.field);
      this.popoverRef = this._inputElementRef;
      this.popoverVisible = false;
      const sub$ = this.afterClose$.subscribe((): void => {
        this.currentFilter = null;
        sub$.unsubscribe();
      });
      this.genIsFilterPanel(false);
      this.popoverVisible = true;
      this._cdr.markForCheck();
    }
    this.clearInput();
  }

  /**
   * 所有过滤器选择值后的回调
   * 1、对应筛选器tag标签修改
   *  如果value值不存在：删除当前过滤器tag，可选择过滤器集合中重新添加当前过滤器
   *  如果value值存在,且处于修改场景：替换之前的label显示，删除原先保存的过滤器结果
   *  如果value存在，且不处于修改场景：刷新tag为过滤器+value值显示
   * 2、保存当前过滤器及过滤结果
   * 3、标记_isModify为false，并触发lvOnChange事件
   * 4、关闭popover下拉面板并设置isFilterPanel为false
   * @param value 筛选器的筛选值
   * @param label 筛选器值的tag展示
   */
  onFilterConfirm(value: any, label: string): void {
    const filterTagIndex = this.tags.findIndex((item): boolean => item.field === this.currentFilter.field);
    const currentTag = this.tags[filterTagIndex];
    const _tempIsModify = this._isModify;

    if (this.filterMode) {
      this.currentFilter.filterMode = this.filterMode;
    }

    if (isEmpty(value) || value.length === 0) {
      this.currentFilter.filteredValue = '';
      this.tags.splice(filterTagIndex, 1);
      this._addFilter(this.currentFilter.field);
    } else {
      if (this._isModify) {
        currentTag.label = `${currentTag.label.split(':')[0]}: ${label}`;
        const index = this.getCurrentFilterIndex();
        if (index !== -1) {
          this._selectedFilters.splice(index, 1);
        }
        this._isModify = false;
      } else {
        currentTag.label += label;
      }
      this.currentFilter.filteredValue = value;
      this._selectedFilters.push({ ...this.currentFilter });
    }

    this._inputElementRef.nativeElement.scrollIntoView({ block: 'nearest', inline: 'nearest' });
    this.popoverRef = this._inputElementRef;
    this.lvOnChange.emit({ selectedFilters: this._selectedFilters, currentFilter: { ...this.currentFilter } });
    this.currentFilter.field = undefined;
    this.renderTagMaxWidth();

    this.togglePopoverVisible();
    this.genIsFilterPanel(false);
    // 修改tag场景下点击确认，需要判断是否需要showLess且不自动展开新的下拉面板；非修改tag场景点击确认，自动展开新的下拉面板
    _tempIsModify ? this.showLess() : this.togglePopoverVisible();
    this._cdr.markForCheck();
  }

  private getTagIndex(): number {
    return this.tags.findIndex((item): boolean => item.field === this.currentFilter?.field);
  }

  private getCurrentFilterIndex(): number {
    return this._selectedFilters.findIndex((item): boolean => item.field === this.currentFilter.field);
  }

  private renderTagMaxWidth(): void {
    setTimeout((): void => {
      this.lvTag.forEach((item): void => {
        const tagItem = (item.nativeElement as HTMLElement).querySelector('.lv-tag-item') as HTMLElement;
        this.render.setStyle(tagItem, 'max-width', this.lvTagMaxWidth);
      });
    });
  }

  private openPopoverByTagIndex(index: number): void {
    setTimeout((): void => {
      if (index !== -1) {
        this.popoverVisible = false;
      }
      this.manualItemClick = false;
      this.lvTag
        .get(index === -1 ? this.lvTag.length - 1 : index)
        .nativeElement.querySelector('.lv-tag-item')
        .dispatchEvent(new Event('click'));
    });
  }

  /**
   * 删除匹配value的子节点，若子节点删除后其父节点为空，父节点删除
   */
  private deleteNodeByValue(arr: any[], value: string, keyName: string = 'value'): void {
    for (let i = arr.length - 1; i >= 0; i--) {
      if (arr[i]?.[keyName] === value) {
        arr.splice(i, 1);
        return;
      }

      if (arr[i].children) {
        this.deleteNodeByValue(arr[i].children, value, keyName);
        if (arr[i].children.length === 0) {
          arr.splice(i, 1);
        }
      }
    }
  }

  /**
   * 根据field往可选择的过滤器集合中添加过滤器选项，添加顺序满足原始顺序
   */
  private _addFilter(field: string | number): void {
    const tempFilters = this.lvFields.map((item): any => ({
      label: item.label,
      value: item.field,
      isLeaf: true,
      disabled: item.disabled,
    }));

    const fields = this.filters.map((item): any => item.value);
    this.filters = tempFilters.filter((item): boolean => fields.includes(item.value) || item.value === field);
    this.treeFilters = this.getTreeFilters({ includeFields: this.filters.map((item): any => item.value) });
  }

  /**
   * 移除所有循环引用的parent
   */
  private removeLoopReferences(obj: { [key: string]: any }): void {
    if (obj && (TypeUtils.isArray(obj) || TypeUtils.isObject(obj))) {
      if (TypeUtils.isArray(obj)) {
        obj.forEach((item): void => {
          this.removeLoopReferences(item);
        });
        return;
      }

      obj?.parent && delete obj.parent;

      Object.keys(obj).forEach((key): void => {
        if (obj[key] && (TypeUtils.isArray(obj[key]) || TypeUtils.isObject(obj[key]))) {
          this.removeLoopReferences(obj[key]);
        }
      });
    }
  }

  private setCurrentFilter(tag: FilterTagItem, filter?: FilterState): void {
    if (filter) {
      this.currentFilter = {
        field: filter.field,
        fieldInfo: filter.fieldInfo,
        filterMode: filter.filterMode,
        type: filter.type,
      };
    } else {
      const originFilter = this.lvFields.find((item): boolean => item.field === tag.field);
      this.currentFilter = {
        field: originFilter?.field || tag.field,
        fieldInfo: originFilter || { field: tag.field, type: 'textInput', modeChangeDisable: true },
        filterMode: originFilter?.mode || 'contains',
        type: originFilter?.type || 'textInput',
      };
    }
  }

  private doAfterFindTag(selectedFilter: OptionItem, cb: (tagIndex: number, tagItem: FilterTagItem) => void): void {
    const tagIndex = this.tags.findIndex((item): boolean => item.field === selectedFilter.value);
    if (tagIndex !== -1) {
      this._isModify = true;
      cb(tagIndex, this.tags[tagIndex]);
    } else {
      this._isModify = false;
      this.filters.splice(
        this.filters.findIndex((item): boolean => item.value === selectedFilter.value),
        1,
      );

      this.deleteNodeByValue(this.treeFilters, selectedFilter.value);

      const newTag: FilterTagItem = {
        label: `${selectedFilter.label}: `,
        field: selectedFilter.value,
        removable: true,
      };
      this.tags.push(newTag);
      cb(tagIndex, newTag);
    }
  }
}
